﻿#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.GamerServices;
#endregion

namespace TunnelsOfDeath.Objects
{
    /// <summary>
    /// This class represents single animated object on game map.
    /// </summary>
    class Sprite : IComparable
    {
        protected int mainTextureID = -1;
        protected Dictionary<Direction, Vector2> animationTable = new Dictionary<Direction, Vector2>();
        protected Dictionary<Direction, int> animationFrames = new Dictionary<Direction, int>();
        protected int animationFrame = 0;
        protected double animationDelay = 5;
        protected double animationTimer = 0;
        public ObjectType Type {get;set;}
        public Vector2 position { get; set; }
        public Direction ObjectDirection { get; set; }
        private double handledTag  = -1;

        public Sprite(
            int _textureID,
            Dictionary<Direction, Vector2> _animationTable,
            Dictionary<Direction,int> _animationFrames,
            ObjectType _type,
            Vector2 _position,
            double _dealy)
        {
            animationTable = _animationTable;
            animationFrames = _animationFrames;
            Type = _type;
            mainTextureID = _textureID;
            position = _position;
            ObjectDirection = Direction.stopped;
            animationDelay = _dealy;
            animationFrame = 1;

        }
        
        public virtual void Draw(SpriteBatch _sp, ViewPosition _view)
        {
            Rectangle sourceRectangle = new Rectangle((int)animationTable[ObjectDirection].X, (int)animationTable[ObjectDirection].Y, (int)(Globals.OBJECTAREA), (int)(Globals.OBJECTAREA));
            if (animationFrame > 1)
            {
                sourceRectangle.X += ((int)animationFrame * (int)Globals.OBJECTAREA)-(int)Globals.OBJECTAREA;
            }
            Vector2 nonScaledPosition = this.position * Globals.OBJECTAREA + _view.Position;
            if (nonScaledPosition.X < 0)
            {
                float areaToCut = Math.Abs(nonScaledPosition.X);
                sourceRectangle.X += (int)areaToCut;
                sourceRectangle.Width -= (int)areaToCut;
                nonScaledPosition.X += areaToCut;

            }
            if (this.Type == ObjectType.explosion && animationFrame > 1)
                Console.Write("");
            Vector2 screenPosition = nonScaledPosition * Globals.ScreenRatio;
            screenPosition += _view.GetScreen();
            _sp.Draw(Globals.Textures[mainTextureID],screenPosition,sourceRectangle,Color.White,0.0f,new Vector2(0,0),Globals.ScreenRatio,SpriteEffects.None,1.0f);
        }

        public virtual void Update(GameTime _gameTime)
        {


            if (animationFrames[ObjectDirection] > 1)
            {
                if (animationTimer < _gameTime.TotalGameTime.TotalMilliseconds)
                {

                    animationFrame++;

                    if (animationFrame > animationFrames[ObjectDirection])
                    {
                        animationFrame = 1;
                    }


                    animationTimer = _gameTime.TotalGameTime.TotalMilliseconds + animationDelay;
                }
            }
            else
            {
                animationFrame = 1;
            }

        }

        public virtual void UpdatePosition(double _tag)
        {
            Globals.PositionUpdate.Remove(this);
        }

        public virtual void RegisterPosition()
        {
            Globals.ObjectManager.RegisterObject(this);
        }

        public virtual void MoveTo(Vector2 _location)
        {
            WakeUpNeighbours();

            Globals.Map[(int)position.X,(int)position.Y] = null;
            position = _location;
            RegisterPosition();

        }

        protected IEnumerable<Vector2> GetAllFieldsAround()
        {
                yield return new Vector2(-1,-1);
                yield return new Vector2(0,-1);
                yield return new Vector2(1,-1);
                yield return new Vector2(-1,0);
                yield return new Vector2(1,0);
                yield return new Vector2(-1,1);
                yield return new Vector2(0,1);
                yield return new Vector2(1, 1);
        }

        protected IEnumerable<Vector2> GetAllFieldsAroundCenter()
        {
            foreach (Vector2 item in GetAllFieldsAround())
            {
                yield return item;
            }
            yield return this.position;
        }

        protected void WakeUpNeighbours()
        {
            foreach (Vector2 item in GetAllFieldsAround())
            {
                if (Globals.Map[(int)position.X + (int)item.X, (int)position.Y + (int)item.Y] != null && Globals.PositionUpdate.IndexOf(Globals.Map[(int)position.X + (int)item.X, (int)position.Y + (int)item.Y]) == -1)
                {
                    Globals.Map[(int)position.X + (int)item.X, (int)position.Y + (int)item.Y].CheckTag(handledTag);
                    Globals.PositionUpdate.Add(Globals.Map[(int)position.X + (int)item.X, (int)position.Y + (int)item.Y]);
                }
            }
        }

        public bool CheckTag(double _tag)
        {
            if (handledTag == _tag)
                return true;
            handledTag = _tag;
            return false;
        }

        public double GetTag()
        {
            return handledTag;
        }

        public int CompareTo(object _object)
        {
            float y1 = this.position.Y;
            float y2 = ((Sprite)_object).position.Y;

            return (Comparer<float>.Default.Compare(y1, y2));
        }

    }
}
